//! gameboy timer

pub struct Timer {
    divider: u8,
    counter: u8,
    modulo: u8, // what the fuck is this ?

    enabled: bool,
    step: u32,
    internalcnt: u32,
    internaldiv: u32,

    pub interrupt: u8,
}

impl Timer {
    pub fn new() -> Self {
        Self {
            divider: 0,
            counter: 0,
            modulo: 0,

            enabled: false,
            step: 1024,
            internalcnt: 0,
            internaldiv: 0,

            interrupt: 0,
        }
    }

    pub fn rb(&self, addr: u16) -> u8 {
        match addr {
            0xFF04 => self.divider,
            0xFF05 => self.counter,
            0xFF06 => self.modulo,
            0xFF07 => {
                0xF8 | (if self.enabled { 0x4 } else { 0 })
                    | (match self.step {
                        16 => 1,
                        64 => 2,
                        256 => 3,
                        _ => 0,
                    })
            }

            _ => {
                //unimplemented!("Timer does not handler read {:4X}", addr);
                0
            }
        }
    }

    pub fn wb(&mut self, addr: u16, value: u8) {
        match addr {
            0xFF04 => {
                self.divider = 0;
            }
            0xFF05 => {
                self.counter = value;
            }
            0xFF06 => {
                self.modulo = value;
            }
            0xFF07 => {
                self.enabled = value & 0x4 != 0;
                self.step = match value & 0x3 {
                    1 => 16,
                    2 => 64,
                    3 => 256,
                    _ => 1024,
                }
            }

            _ => {
                unimplemented!("Timer does not handle read {:4X}", addr);
            }
        }
    }

    pub fn do_cycle(&mut self, ticks: u32) {
        self.internaldiv += ticks;

        while self.internaldiv >= 256 {
            self.divider = self.divider.wrapping_add(1);
            self.internaldiv -= 256;
        }

        if self.enabled {
            self.internalcnt += ticks;

            while self.internalcnt >= self.step {
                self.counter = self.counter.wrapping_add(1);

                if self.counter == 0 {
                    self.counter = self.modulo;
                    self.interrupt |= 0x04;
                }
                self.internalcnt -= self.step;
            }
        }
    }
}
